#include "TextQuery.h"


/**
 * @brief 
 * 
 * @param ctr 
 * @param word 
 * @param ending 
 * @return std::string 
 */
std::string make_plural(size_t ctr, const std::string &word, const std::string &ending)
{
    return (ctr > 1) ? word + ending : word;
}
/**
 * @brief Construct a new Text Query:: Text Query object
 *        read the input file and build the map of lines to line numbers
 * @param is 
 */
TextQuery::TextQuery(std::ifstream &is)
    : file(new std::vector<std::string>)
{
    std::string text;
    while (std::getline(is, text))
    {
        file->push_back(text);
        int n = file->size() - 1;
        std::istringstream line(text);
        std::string word;
        while (line >> word)
        {
            word = cleanup_str(word);
            std::shared_ptr<std::set<TextQuery::line_no>> &lines = wm[word];
            if (!lines)
            {
                lines.reset(new std::set<line_no>);
            }
            lines->insert(n);
        }
    }
}
/**
 * @brief 
 * 
 * @param word 
 * @return std::string 
 */
std::string TextQuery::cleanup_str(const std::string &word)
{
    std::string ret;
    for(auto iter = word.begin(); iter != word.end(); ++iter)
    {
        if(!ispunct(*iter))
        {
            ret += tolower(*iter);
        }
    }
    return ret;
}
/**
 * @brief 
 * 
 * @param sought 
 * @return QueryResult 
 */
QueryResult TextQuery::query(const std::string &sought) const
{
    static std::shared_ptr<std::set<TextQuery::line_no> > nodata(new std::set<line_no>);
    auto loc = wm.find(cleanup_str(sought));
    if(loc == wm.end())
    {
        return QueryResult(sought, nodata, file);
    }
    else
    {
        return QueryResult(sought, loc->second, file);
    }
    
}
/**
 * @brief 
 * 
 * @param os 
 * @param qr 
 * @return std::ostream& 
 */
std::ostream &print(std::ostream &os, const QueryResult &qr)
{
    os << qr.sought << " occurs " << qr.lines->size() << " "
       << make_plural(qr.lines->size(), "time", "s") << std::endl;
    
    for(auto num = qr.lines->begin(); num != qr.lines->end(); ++num)
    {
        os << "\t(line" << *num + 1 << ") " << *(qr.file->begin() + *num) << std::endl;
    }
    return os;
}
/**
 * @brief 
 * 
 */
void TextQuery::display_map()
{
    auto iter_begin = wm.begin(), iter_end = wm.end();
    for( ; iter_begin != iter_end; ++iter_begin)
    {
        std::cout << "word: " << iter_begin->first << "{ ";
        auto text_locs = iter_begin->second;
        auto loc_iter_begin = text_locs->begin(), loc_iter_end = text_locs->end();
        while(loc_iter_begin != loc_iter_end)
        {
            std::cout << *loc_iter_begin;
            if(++loc_iter_begin != loc_iter_end)
            {
                std::cout << ", ";
            }
        }
        std::cout << "}\n";
    }
    std::cout << std::endl;
}